package com.infore.maintenance.main.utils.parsesql;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import org.ssssssss.script.functions.StreamExtension;
import org.ssssssss.script.parsing.GenericTokenParser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 普通SQL节点
 *
 * @author jmxd
 * @version : 2020-05-18
 */
public class TextSqlNode extends SqlNode {
	private static final Pattern REPLACE_MULTI_WHITE_LINE = Pattern.compile("(\r?\n(\\s*\r?\n)+)");

	private static final GenericTokenParser CONCAT_TOKEN_PARSER = new GenericTokenParser("${", "}", false);

	private static final GenericTokenParser REPLACE_TOKEN_PARSER = new GenericTokenParser("#{", "}", true);

	/**
	 * SQL
	 */
	private final String sql;

	public TextSqlNode(String text) {
		this.sql = text;
	}

	public static String parseSql(String sql, Map<String, Object> varMap, List<Object> parameters) {
		// 处理${}参数
		sql = CONCAT_TOKEN_PARSER.parse(sql, text -> String.valueOf(ScriptManager.executeExpression(text, varMap)));
		// 处理#{}参数
		sql = REPLACE_TOKEN_PARSER.parse(sql, text -> {
			Object value = ScriptManager.executeExpression(text, varMap);
			if (value == null) {
				parameters.add(null);
				return "?";
			}
			try {
				//对集合自动展开
				List<Object> objects = StreamExtension.arrayLikeToList(value);
				parameters.addAll(objects);
				return IntStream.range(0, objects.size()).mapToObj(t -> "?").collect(Collectors.joining(","));
			} catch (Exception e) {
				parameters.add(value);
				return "?";
			}
		});
		sql = sql == null ? null : REPLACE_MULTI_WHITE_LINE.matcher(sql.trim()).replaceAll("\r\n");
		return sql;
	}


	/**
	 * 替换sql中的占位符
	 * @param sql
	 * @return
	 */
	public static String replaceSqlPlaceholder(String sql) {
		// 处理#{}参数
		sql =REPLACE_TOKEN_PARSER.parse(sql, text -> {
			return text;
		});
		// 处理${}参数
		sql =CONCAT_TOKEN_PARSER.parse(sql, text -> {
			return text;
		});
		return sql;
	}

	/**
	 * 解析sql中占位符中的参数
	 * @param sql
	 * @param varMap
	 * @param parameters
	 * @return
	 */
	public static String parseSqlParamenters(String sql, Map<String, Object> varMap, Map<String, Object> parameters) {
		// 处理#{}参数
		sql =REPLACE_TOKEN_PARSER.parse(sql, text -> {
			Object value  = varMap.get(text);
			if (value == null) {
				parameters.put(text,null);
			}else{
				// in 参数值为数组需要拼接SQL不能用占位符
				if(value instanceof JSONArray || value instanceof List){
					Object[] objects = JSONUtil.parseArray(value).toArray();
					StringBuilder sbIn = new StringBuilder();
					for (int i = 0; i <objects.length ; i++) {
						if (i == objects.length - 1) {
							sbIn.append("'").append(objects[i]).append("'");
						} else {
							sbIn.append("'").append(objects[i]).append("'").append(",");
						}
					}
					parameters.put(text,sbIn.toString());
					return sbIn.toString();
				}else{
					parameters.put(text,value);
				}
			}
			return "#{map."+text+"}";
		});
		// 处理${}参数
		sql =CONCAT_TOKEN_PARSER.parse(sql, text -> {
			Object value  = varMap.get(text);
			if (value == null) {
				parameters.put(text,null);
			}else{
				// in 参数值为数组需要拼接SQL不能用占位符
				if(value instanceof JSONArray || value instanceof List){
					Object[] objects = JSONUtil.parseArray(value).toArray();
					StringBuilder sbIn = new StringBuilder();
					for (int i = 0; i <objects.length ; i++) {
						if (i == objects.length - 1) {
							sbIn.append("'").append(objects[i]).append("'");
						} else {
							sbIn.append("'").append(objects[i]).append("'").append(",");
						}
					}
					parameters.put(text,sbIn.toString());
					return sbIn.toString();
				}else{
					parameters.put(text,value);
				}
			}
			return "#{map."+text+"}";
		});
		return sql;
	}

	@Override
	public String getSql(Map<String, Object> paramMap, List<Object> parameters) {
		return parseSql(sql, paramMap, parameters) + executeChildren(paramMap, parameters).trim();
	}

	public static void main(String[] args) {
//		String sql = "select * from data_maintain.t_base_datasource \n" +
//				" where database_type= #{databaseType}";
		String sql = "select RULE_ID as \"role_id\",CONTINUE_NUM as \"continue_num\",DATA_TYPE as \"data_type\",\n" +
				"       PROJECT_ID as \"project_id\",PROJECT_NAME as \"project_name\" from basic_db.t_basic_rule_detail_oth\n" +
				"where ( '${ruleId}' is null or RULE_ID= '${ruleId}') and PROJECT_ID in  (#{projectId})";
		Map<String, Object> varMap = new HashMap<>();
		varMap.put("ruleId","21468BB7034848FB89547663283483F1");
		List<Object> in = new ArrayList<>();
		in.add("aaa");
		in.add("vv");
		varMap.put("projectId",in);
		Map<String, Object> parametersMap = new HashMap<>();
//		sql = parseSql(sql,varMap,parameters);
		String executeSql = parseSqlParamenters(sql, varMap, parametersMap);


		System.out.println(executeSql);

	}
}
